# 项目中一些自定义中间件
from datetime import datetime, timezone, timedelta
from tokenize import TokenError

import jwt
from django.utils.deprecation import MiddlewareMixin
from rest_framework_simplejwt.tokens import AccessToken

from Django_demo01 import settings
from utils.ResponseResult import fail_result_json


# jwt token验证中间件
class JWTAuthenticationMiddleware(MiddlewareMixin):

    def process_request(self, request):
        print(f"自定义中间件[JWTAuthenticationMiddleware],请求开始执行 ...")
        # 不需要校验的路径可通过请求头专用字段或将无须校验路径的路径放缓存中
        # /admin/  django自带管理系统地址
        if request.path.startswith('/auth/login1') or request.path.startswith('/admin/'):
            return self.get_response(request)

        # 获取 Authorization 头(key为settings中配置的AUTH_HEADER_NAME)
        # 也可以通过request.headers.get('Authorization')获取 key为前端传的
        auth_header = request.META.get('HTTP_AUTHORIZATION')
        if not auth_header:
            return fail_result_json(msg="认证失效，请登录后访问", code=401)
        try:
            # 解析 token
            # token = auth_header.split(' ')[1]
            # access_token = AccessToken(auth_header)
            # user_id = access_token.payload.get('user_id')
            # print(f"用户信息：{user_id}")
            payload = jwt.decode(auth_header, settings.SECRET_KEY, algorithms='HS256')
            if not payload or 'user_id' not in payload:
                return fail_result_json(msg="认证失效，请重新登录", code=403)

            # 检查iat 是否合理
            iat = payload.get('iat')
            if not iat:
                return fail_result_json(msg="无效认证信息，请重新登录", code=403)
            iat_datetime = datetime.fromtimestamp(iat, timezone.utc)
            # 检查 iat 是否在合理的时间范围内
            current_time = datetime.now(timezone.utc)
            # 当前时间与令牌签发时间的差值不能大于1小时（防止重放攻击，确保令牌新鲜性）
            if current_time - iat_datetime > timedelta(hours=1):
                raise fail_result_json(msg="认证已过期，请重新登录", code=403)

            # 检查token是否过期
            exp = payload.get('exp')
            if not exp:
                return fail_result_json(msg="无效认证信息，请重新登录", code=403)
            # 将 exp 转换为 datetime 对象
            exp_datetime = datetime.fromtimestamp(exp, timezone.utc)
            # 检查令牌是否已过期
            if current_time > exp_datetime:
                return fail_result_json(msg="认证过期，请重新登录", code=401)

            user_info = {
                'id': payload['user_id'],
                'user_no': payload['user_no'],
                'user_name': payload['user_name'],
                'email': payload['email'],
                'phone': payload['phone'],
                'role_id': payload['role_id'],
                'status': payload['status'],
                'create_date': payload['create_date'],
                'exp': (datetime.fromtimestamp(payload['exp'], timezone.utc)).strftime("%Y-%m-%d %H:%M:%S"),
                'iat': (datetime.fromtimestamp(payload['iat'], timezone.utc)).strftime("%Y-%m-%d %H:%M:%S")
            }
            request.user_info = user_info
        except TokenError as e:
            return fail_result_json(msg=f"认证失效，{e}，请重新登录", code=401)
        except Exception as e:
            return fail_result_json(msg=f"认证失效，{e}，请联系管理员", code=401)

        # 继续处理请求
        response = self.get_response(request)
        return response

    def process_response(self, request, response):
        print(f"自定义中间件[{self.__class__.__name__}],请求执行结束 ...")
        return response
